package com.flaskpy.web.eternity.auth.jwt.config;

import com.flaskpy.web.eternity.auth.jwt.config.filter.JwtExceptionFilter;
import com.flaskpy.web.eternity.auth.jwt.service.IAccessDecisionService;
import com.flaskpy.web.eternity.auth.jwt.service.IJwtAuthicationService;
import com.flaskpy.web.eternity.auth.jwt.service.IOnLineService;
import com.flaskpy.web.eternity.auth.jwt.service.impl.*;
import com.flaskpy.web.eternity.auth.jwt.util.TokenProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository;

import java.util.ArrayList;
import java.util.List;

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true) //开启方法注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 授权配置
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);

    }

    /**
     * 认证配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       //AffirmativeBased
        http.securityContext().securityContextRepository(securityContextRepository());//硬塞SecurityContext完成认证
        http.csrf().disable();
        http.authorizeRequests().anyRequest().authenticated();//所有都经Voter授权
        http.addFilterBefore(jwtExceptionFilter(), SecurityContextPersistenceFilter.class);

        http.authorizeRequests().accessDecisionManager(accessDecisionManager());
    }



    /**
     * 权限签定管理器(面向web) 一票通过
     * @return
     */
    @Bean
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();

        decisionVoters.add(rbacVoter());    //rbac投票
        decisionVoters.add(new WebExpressionVoter());

        decisionVoters.add(new Jsr250Voter());

        RoleVoter roleVoter = new RoleVoter();
        roleVoter.setRolePrefix("ROLE_");

        decisionVoters.add(roleVoter);
        decisionVoters.add(new AuthenticatedVoter());
        return new AffirmativeBased(decisionVoters);
    }
    @Bean
    public RbacVoter rbacVoter(){
        return new RbacVoter();
    }
    @ConditionalOnMissingBean
    @Bean
    public IOnLineService onLineService(){
        return new DefaultOnLineServiceImpl();
    }

    @ConditionalOnMissingBean
    @Bean
    public IAccessDecisionService accessDecisionService(){
        return new DefaultAccessDecisionServiceImpl();
    }

    @Bean
    public JwtExceptionFilter jwtExceptionFilter(){
        return new JwtExceptionFilter();
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new DefaultPasswordEncoderImpl();
    }
    @Bean
    public SecurityContextRepository securityContextRepository(){
        return new JwtContextRepositoryImpl();
    }
    @Bean
    public IJwtAuthicationService userDetailsService(){
        return new JwtUserDetailServiceImpl();
    }
    @Bean
    public TokenProvider tokenProvider(){
        return new TokenProvider();
    }
}
